#include<iostream>//poj3035
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<assert.h>
#include<cmath>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
const int inf=1000000000;
const double pi=acos(-1.0);
#define eps (1e-15)
#define L(x) ((x)<<1)
#define R(x) ((x)<<1|1)
#define clr(x,a) memset(x,a,sizeof(x))
#define see(x)(cerr<<"[line:"<<__LINE__<<" "<<#x<<" "<<x<<endl)
#define se(x) cerr<<x<<" "
#define sz(x) (int)x.size()
#define pb push_back
template<class T>void show(T a, int n){for(int i=0; i<n; ++i) cout<<a[i]<<' '; cout<<endl;}
template<class T>void show(T a, int r, int l){for(int i=0; i<r; ++i)show(a[i],l);cout<<endl;}

inline int to_i(const string& s)
{int n;sscanf(s.c_str(),"%d",&n);return n;}
inline string to_s(int n)
{char buf[32];sprintf(buf,"%d",n);return string(buf);}
inline int rd(){int x;scanf("%d",&x);return x;}

const int maxe = 8000010;
const int maxv=  2200100;
const int mr=620;
int n,m,S,T;

int first[maxv],next[maxe],C[maxe],M,E[maxe];
void initedge()
{
    M=-1;
    memset(first,-1,sizeof(first));
}
void _insert(int a,int b,int c)
{
    M++;
    next[M]=first[a];
    first[a]=M;
    C[M]=c;
    E[M]=b;
    //Ef[M]=a;
}
void insert(int i,int j,int c)
{
    _insert(i,j,c);
    _insert(j,i,c);
}

/***********平面图最小割模板*******************/
int g[mr][mr][4],edge,dot;//dot是点数,g记录方格对应的标号
void init()//初始话边权,
{//n是方格的行数,m是方格的列数
    int i,j,k;//n是方格的行数,m是方格的列数
    int tp=1;
    S=tp++; T=tp++;
    for(k=0; k<4; k++)  
    {
		for(i=1;i<=m+1; i++)
			g[0][i][k]=S;
		for(i=1; i<=n; i++)
			g[i][m+1][k]=S;
		
		for(i=1; i<=n+1; i++)
			g[i][0][k]=T;
		for(i=0; i<=m; i++)
			g[n+1][i][k]=T;
    }
    
	for(i=1; i<=n; i++)
		for(j=1; j<=m; j++)
		for(k=0; k<4; k++)	
			g[i][j][k]=tp++;
    dot=tp+2;//设置点数
}

/***********平面图最小割模板*******************/



struct node
{
	int u,a;
	node(){}
	node(int aa,int bb)
	{ u=aa; a=bb;}
	bool operator<(const node &b)const
	{	return a>b.a;}
};
priority_queue<node>q;int dis[maxv];
int spfa()
{
	while(!q.empty())	q.pop();
	memset(dis,-1,sizeof(dis));
	int i,j,e,s=S,t=T;
	dis[s]=0;
	node a;
	q.push(node(s,0));
	while(!q.empty())
	{
		a=q.top(); q.pop();
		int u=a.u;
		if(a.u==T)	return dis[T];
		for(e=first[u]; e!=-1; e=next[e])
		{
			int v=E[e];
			if(dis[u]+C[e]<dis[v]||dis[v]==-1)
			{
				dis[v]=dis[u]+C[e];
				q.push(node(v,dis[v]));
			}
		}
	}
}
int main()
{
    //freopen("in","r",stdin);
    int i,j,k,t;
    while(scanf("%d%d", &n,&m)!=EOF)
    {
        init();
        initedge();
        int x,y;
		for(i=0; i<=n; i++)
			for(j=1; j<=m; j++)
			{
				x=rd();
				insert(g[i][j][2],g[i+1][j][0],x);
			}
        
		for(i=1; i<=n; i++)
			for(j=0; j<=m ;j++)      
			{
				x=rd();
				insert(g[i][j][1],g[i][j+1][3],x);
			}
		for(i=1; i<=n; i++)
		{
			for(j=1; j<=m ;j++)
			{
				x=rd(); y=rd();
				insert(g[i][j][0],g[i][j][3],x);
				insert(g[i][j][0],g[i][j][1],y);
			}
			
			
			for(j=1; j<=m ;j++)
			{
				x=rd(); y=rd();
				insert(g[i][j][2],g[i][j][3],x);
				insert(g[i][j][2],g[i][j][1],y);
			}	
		}
       
        printf("%d\n", spfa());
    }        
}
